import {BaseManager, getManager, manager} from "../../coreModule/managers/BaseManager";
import {Certification, Identification, User} from "../data/User";
import {storageMgr} from "../../coreModule/managers/StroageManager";
import {UserInterface} from "../UserCommon";
import {blockLoading, showLoading} from "../../coreModule/managers/LoadingManager";
import {appMgr} from "../../coreModule/managers/AppManager";
import {handleError} from "../../coreModule/managers/AlertManager";
import {DataLoader} from "../../coreModule/data/DataLoader";
import {PromiseUtils} from "../../../utils/PromiseUtils";

export function waitForLogin(obj, key, desc) {
	const oriFunc = desc.value;
	desc.value = async function (...p) {
		await PromiseUtils.waitFor(() => userMgr().isLogin);
		return await oriFunc.apply(this, p);
	}
}

export function userMgr() {
	return getManager(UserManager)
}

const UserInfoKey = "userInfo";
const OpenidKey = "openid";

@manager
export class UserManager extends BaseManager {

	/**
	 * 用户
	 */
	// TODO: 这种写法能否使用修饰器简化？
	private _userInfo: User;
	public get userInfo(): User {
		return this._userInfo ||= storageMgr().getData(UserInfoKey, User);
	}
	public set userInfo(val: User) {
		storageMgr().setData(UserInfoKey, this._userInfo = val);
	}

	/**
	 * openid
	 */
	private _openid: string;
	public get openid() {
		return this._openid ||= storageMgr().getData(OpenidKey);
	}
	public set openid(val: string) {
		storageMgr().setData(OpenidKey, this._openid = val);
	}

	public savedInviteCode: string
	public location: {
		province: string,
		city: string
	}

	// region 用户操作

	/**
	 * 是否已经登录
	 */
	public get isLogin() {
		return !!this._userInfo && !!appMgr().getToken();
	}

	/**
	 * 登陆
	 * 登陆只会执行一次，要想重新登录，必须先登出
	 */
	@showLoading
	@blockLoading
	@handleError(true)
	public async login(userInfo?: Partial<User>) {
		// 如果已经登陆了，直接返回用户数据
		if (this.isLogin) return this.userInfo;

		// 如果没有userInfo缓存，则自动登陆失败
		if (!(userInfo ||= this.userInfo)) return null;
		// 否则，可以进行自动登录

		// 如果没有openid缓存，手动获取openid
		this.openid ||= await this.getUserOpenid();

		const res = await UserInterface.Login({
			openid: this.openid, userInfo
		});
		appMgr().setupToken(res.token);

		res.user.certification = res.certification;
		res.user.identification = res.identification;
		const user = DataLoader.load(User, res.user);
		return this.userInfo = user;
	}

	/**
	 * 登出
	 */
	public async logout() {
		if (!this.isLogin) return;
		await UserInterface.Logout();
		appMgr().clearToken();
		this.userInfo = null;
	}

	/**
	 * 手动登录
	 */
	@showLoading
	@blockLoading
	public async manualLogin(desc?: string) {
		const profile = await wx.getUserProfile({
			desc, // 声明获取用户个人信息后的用途，会展示在弹窗中，请谨慎填写
		});
		console.log("manualLogin profile", profile);
		// 如果已经登陆了，先登出
		if (this.isLogin) await this.logout();
		return this.login(profile.userInfo);
	}

	/**
	 * 获取手机号
	 */
	public async getPhone(code: string) {
		const res = await UserInterface.GetPhoneNumber({code})
		return res.phone;
	}

	/**
	 * 刷新个人信息
	 */
	public async refresh() {
		if (!this.isLogin) return;
		const res = await UserInterface.GetInfo();
		res.user.certification = res.certification;
		res.user.identification = res.identification;
		const user = DataLoader.load(User, res.user);
		return this.userInfo = user;
	}

	/**
	 * 获取用户openid
	 */
	private async getUserOpenid() {
		const code = (await this.wxLoginPromise()).code;
		const codeRes = await UserInterface.Code2Session({code});
		console.log("codeRes:", codeRes);
		return codeRes.openid;
	}
	private wxLoginPromise() {
		return new Promise<any>(resolve => {
			wx.login({success: resolve});
		})
	}

	// endregion

	// region 认证操作

	/**
	 * 实名认证
	 */
	public async authIdent(data: Identification) {
		const res = await UserInterface.AuthIdent({data});
		data = DataLoader.load(Identification, res["data"]);

		this.userInfo.setupIdent(data);
	}

	/**
	 * 实名认证
	 */
	public async authCert(data: Certification) {
		const res = await UserInterface.AuthCert({data});
		data = DataLoader.load(Certification, res["data"]);

		this.userInfo.setupCert(data);
	}

	// endregion

}
